// (c) Copyright 2013 Mike Riedel.
// This source is subject to the Microsoft Public License (Ms-PL).
// All other rights reserved.

using FreshMeat.MiniHsm;

namespace FreshMeat.MiniHsmTest
{
   class Pelican : MiniMachine<Pelican.Input>
   {
      public enum Input
      {
         GetParent = -4,
         SetDefault,
         Enter,
         Exit,
         PedWaiting,
         TimerExpired,
         PowerOff
      }

      public enum Vehicle
      {
         Red,
         Yellow,
         Green
      }

      public enum Ped
      {
         Walk,
         Flash,
         DontWalk
      }

      public Pelican()
         : base(Input.GetParent, Input.SetDefault, Input.Enter, Input.Exit)
      {
         DefaultTo(Operational);
      }

      State Operational(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Power = true;
               Cars = Vehicle.Red;
               Peds = Ped.DontWalk;
               return null;

            case Input.SetDefault:
               DefaultTo(CarsEnabled);
               return null;

            case Input.Exit:
               return null;

            case Input.PowerOff:
               TransitionTo(Off);
               return null;
         }

         return Root;
      }

      State Off(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Power = false;
               return null;
         }

         return Root;
      }

      State CarsEnabled(Input input)
      {
         switch (input)
         {
            case Input.SetDefault:
               DefaultTo(CarsGreen);
               return null;

            case Input.Exit:
               Cars = Vehicle.Red;
               return null;
         }

         return Operational;
      }

      State CarsGreen(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Cars = Vehicle.Green;
               Timer = 30;
               return null;

            case Input.PedWaiting:
               IsPedestrianWaiting = true;
               break;

            case Input.TimerExpired:
               if (IsPedestrianWaiting)
                  TransitionTo(CarsYellow);
               else
                  TransitionTo(CarsGreenInterruptible);
               return null;
         }

         return CarsEnabled;
      }

      State CarsGreenInterruptible(Input input)
      {
         switch (input)
         {
            case Input.PedWaiting:
               TransitionTo(CarsYellow);
               return null;
         }

         return CarsEnabled;
      }

      State CarsYellow(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Cars = Vehicle.Yellow;
               Timer = 5;
               return null;

            case Input.TimerExpired:
               TransitionTo(PedsEnabled);
               return null;
         }

         return CarsEnabled;
      }

      State PedsEnabled(Input input)
      {
         switch (input)
         {
            case Input.SetDefault:
               DefaultTo(PedsWalk);
               return null;

            case Input.Exit:
               Peds = Ped.DontWalk;
               return null;
         }

         return Operational;
      }

      State PedsWalk(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Peds = Ped.Walk;
               Timer = 30;
               return null;

            case Input.TimerExpired:
               TransitionTo(PedsFlash);
               return null;
         }

         return PedsEnabled;
      }

      State PedsFlash(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Peds = Ped.Flash;
               Timer = 5;
               return null;

            case Input.TimerExpired:
               TransitionTo(CarsEnabled);
               return null;
         }

         return PedsEnabled;
      }

      public void Update(Input input)
      {
         Process(input);
      }

      bool IsPedestrianWaiting { get; set; }

      public bool Power { get; private set; }
      public Vehicle Cars { get; private set; }
      public Ped Peds { get; private set; }
      public int Timer { get; private set; }
   }
}